package ru.ds.selenium;

import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.List;

import javax.swing.plaf.basic.BasicScrollPaneUI.HSBChangeListener;

import org.testng.*;
import org.testng.annotations.*;

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;

import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.support.ui.WebDriverWait;

public class SearchTest2 extends ru.ds.selenium.pages.TestBase2 {
  private boolean acceptNextAlert = true;
  private StringBuffer verificationErrors = new StringBuffer();
  private CharSequence movieName = "Renegade";
  private CharSequence movieYear = "2012";
  private final String SEARCH_STRING = "Reneg";
  private final String NAME_INPUT = "name";
  private final String YEAR_INPUT = "year";
  private final String ADD_PAGE_URL_SUFFIX = "go=add";
  private final String WRONG_SEARCH_STRING = "XXX";
  private final String NO_RESULTS = "No movies where found.";
  private final int TEST_MODE_1 = 1;   // test mode for search with results
  private final int TEST_MODE_2 = 2;   // test mode for search without results
  
  private List<String> addedMoviesURLs = new ArrayList<String>();
  

  @Test
  public void testSearch() throws Exception {
	//Login procedure
	driver.get(baseUrl + "/php4dvd/");
	WebElement usernameField =  wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//input[@id='username']")));
	usernameField.clear();
	usernameField.sendKeys("admin");
	WebElement passwordField = wait.until(ExpectedConditions.presenceOfElementLocated(By.name("password")));
	passwordField.clear();
	passwordField.sendKeys("admin");
	wait.until(ExpectedConditions.presenceOfElementLocated(By.name("submit"))).click();
	//Creating 2 new movies
	addNewMovie(movieName, movieYear);
	addNewMovie(movieName + " 2", movieYear);
	//Performing search for added movies - 2 movies should be found 
	getSearchResultPage(SEARCH_STRING);
	verifySearchResults(TEST_MODE_1);
	//Performing search for non-existing movies - no movies should be found 
	getSearchResultPage(WRONG_SEARCH_STRING);
	verifySearchResults(TEST_MODE_2);
	//Deleting created movies
	wait.until(ExpectedConditions.presenceOfElementLocated(By.linkText("Home"))).click();
	clearSearchField();
	deleteAddedMovies();
	//Logging out
	wait.until(ExpectedConditions.presenceOfElementLocated(By.linkText("Log out"))).click();
    assertTrue(closeAlertAndGetItsText().matches("^Are you sure you want to log out[\\s\\S]$"));
  }

  private boolean isElementPresent(By by) {
    try {
      wait.until(ExpectedConditions.presenceOfElementLocated(by));
      return true;
    } catch (NoSuchElementException e) {
      return false;
    }
  }

  private String closeAlertAndGetItsText() {
    try {
      Alert alert = driver.switchTo().alert();
      String alertText = alert.getText();
      if (acceptNextAlert) {
        alert.accept();
      } else {
        alert.dismiss();
      }
      return alertText;
    } finally {
      acceptNextAlert = true;
    }
  }
  
  private boolean hasAttribute(WebElement we, String attrName) {
	  if(we.getAttribute(attrName) == null) {
		  return false;
	  } else {
		  return true;
	  }
  }
  
  private List<WebElement> getAllInputs() {
	  return wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.tagName("input")));
  }
  
  private void fillNewMovieForm(CharSequence movieName, CharSequence movieYear){
		//required text fields
		WebElement movieNameField = wait.until(ExpectedConditions.presenceOfElementLocated(By.name("name")));
		movieNameField.clear();
		movieNameField.sendKeys(movieName);
		WebElement movieYearField = wait.until(ExpectedConditions.presenceOfElementLocated(By.name("year")));
		movieYearField.clear();
		movieYearField.sendKeys(movieYear);
		//Checkboxes
		if(isElementPresent(By.id("own_no"))) {
			WebElement ownCheckBox = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("own_no")));
			ownCheckBox.click();
		}
		if(isElementPresent(By.id("seen_yes"))) {
			WebElement seenCheckBox = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("seen_yes")));
			seenCheckBox.click();
		}
		if(isElementPresent(By.id("loaned_no"))) {
			WebElement loanCheckBox = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("loaned_no")));
			loanCheckBox.click();
		}
		//Submit
		WebElement submitButton = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("submit")));
		submitButton.click();
  }
  
  private void findAndFillRequiredFields(CharSequence movieName, CharSequence movieYear) {
		for(WebElement we : getAllInputs()) {
			if(hasAttribute(we, "name")) {
				String inputName = we.getAttribute("name");
				if(NAME_INPUT.equals(inputName)) {
					we.clear();
					we.sendKeys(movieName);
				}
				if(YEAR_INPUT.equals(inputName)) {
					we.clear();
					we.sendKeys(movieYear);
				}
			}	
		}
		WebElement submitButton = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("submit")));
		submitButton.click();
  }
  
  private void addNewMovie(CharSequence movieName, CharSequence movieYear) {
	  	wait.until(ExpectedConditions.presenceOfElementLocated(By.linkText("Add movie"))).click();
		fillNewMovieForm(movieName, movieYear);
		if(driver.getCurrentUrl().endsWith(ADD_PAGE_URL_SUFFIX)){
			findAndFillRequiredFields(movieName, movieYear);
		}
		addedMoviesURLs.add(driver.getCurrentUrl());
		wait.until(ExpectedConditions.presenceOfElementLocated(By.linkText("Home"))).click();	  
  }
  
  private void deleteAddedMovies() {
		for(String url : addedMoviesURLs) {
			driver.get(url);
			wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("img[alt=\"Remove\"]"))).click();
			assertTrue(closeAlertAndGetItsText().matches("^Are you sure you want to remove this[\\s\\S]$"));
		}  
  }
  
  private void getSearchResultPage(String searchText) {
	  WebElement searchField = wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//div[@id='search']//input[@id='q']")));
	  searchField.clear();
	  searchField.sendKeys(searchText);
	  try {
			Thread.sleep(2000);
	  } catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
	  }
	  searchField.sendKeys(Keys.RETURN);
	  List<WebElement> lst  = wait.until(ExpectedConditions.refreshed(ExpectedConditions.presenceOfAllElementsLocatedBy(By.xpath(".//div[@id='results']/a"))));
	  try {
			Thread.sleep(2000);
	  } catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
	  }
  }
  
  private void clearSearchField() {
	  WebElement searchField = wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//div[@id='search']//input[@id='q']")));
	  searchField.clear();
	  searchField.sendKeys(Keys.RETURN);
  }
  
  private void verifySearchResults(int testMode) {  
	  List<String> movieNames = new ArrayList<String>();
	  if(testMode == TEST_MODE_1) {
		  List<WebElement> lst = wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.xpath(".//div[@id='results']/a//div[@class='title']")));
		  Assert.assertTrue(lst.size() == 2, "There should be exactly 2 movies returned by search result!");
		  for(WebElement we : lst) {
			movieNames.add(we.getText()); 
		  }
		  Assert.assertTrue(movieName.equals(movieNames.get(0)), "First movie does not have correct name!");
		  Assert.assertTrue((movieName + " 2").equals(movieNames.get(1)), "Second movie does not have correct name!");
	  } else {
		  WebElement divContent = wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//*[@id='results']/div[1]")));
		  String textContent = divContent.getText();
		  Assert.assertTrue(NO_RESULTS.equals(textContent), "There should be " + NO_RESULTS + " message displayed!" ); 
	  }
  }
}



